package com.thinkit.core.handler;
import com.google.common.collect.Lists;
import com.thinkit.core.annotation.NotDecorate;
import com.thinkit.utils.model.ApiResult;
import com.thinkit.utils.utils.Checker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.security.authentication.LockedException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestControllerAdvice
public class ReturnAdviceHandler implements ResponseBodyAdvice<Object> {

	@Override
	public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
		boolean bePrivate = Modifier.PRIVATE == returnType.getMethod().getModifiers();
		if (bePrivate) {
			return false;
		}
		NotDecorate notDecorate = returnType.getMethod().getAnnotation(NotDecorate.class);
		if (notDecorate != null) {
			return false;
		}
		return true;
	}

	@Override
	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
                                  ServerHttpResponse response) {
		if("OPTIONS".equals(request.getMethod())) {
			response.setStatusCode(HttpStatus.OK);
		}
		String path = request.getURI().getPath();
		System.out.println("请求：：：：：：：：：：："+path);
		if(path.startsWith("/swagger-resources")||path.startsWith("/v2/api-docs") || path.startsWith("/actuator")  ){
			return body;
		}

		return returnDecorator(body,response);
	}

	private Object returnDecorator(Object body, ServerHttpResponse response){
        //封装返回结果
		if (ckNull(body)) {
			return ApiResult.result();
		}
		if (isApiResult(body)) {
			return  body;
		}
		if (isCollection(body)) {
			Collection<?> ction = (Collection<?>) body;
			List<?> list;
			if (ction instanceof List && Checker.BeNotNull(ction)) {
				list = (List<?>) ction;
			} else {
				list = Lists.newArrayList(ction);
			}
			return ApiResult.result(list);
		}
		if (isModelAndView(body)) {
			ModelAndView mv = (ModelAndView) body;
			return mv;
		}
		if(isException(body)){
			Exception exception = ((Exception) body);
			if(isSpecifyException(exception,CustomException.class)){
				return customExceptionDecorate(exception,response);
			}
			if(isSpecifyException(exception, LockedException.class)){
				return forbidExDecorate(exception,response);
			}
			return ApiResult.result(-1);
		}
		return ApiResult.result(body);
	}

	private boolean ckNull(Object body){
		return Checker.BeNull(body);
	}

	private boolean isException(Object body){
		return Exception.class.isInstance(body);
	}

	private boolean isSpecifyException(Exception ex,Class clz){
		boolean exce= clz.isInstance(ex);
		boolean cause = false;
		if(Checker.BeNotNull(ex.getCause())){
			cause=clz.isInstance(ex.getCause());
		}
		return exce || cause;
	}

	private ApiResult customExceptionDecorate(Exception exception,ServerHttpResponse response){
		log.error(exception.getMessage());
		log.error("--------------格式化异常----------------------");
		if(Checker.BeNotNull(exception.getCause())&& exception.getCause() instanceof CustomException){
			CustomException customException = (CustomException) exception.getCause();
			response.setStatusCode(HttpStatus.valueOf(customException.getCode()));
			return ApiResult.result(customException.getCode(),exception.getCause().getMessage());
		}else{
			CustomException customException = (CustomException) exception;
			response.setStatusCode(HttpStatus.valueOf(customException.getCode()));
			return ApiResult.result(customException.getCode(),exception.getMessage());
		}
	}

	private ApiResult forbidExDecorate(Exception exception,ServerHttpResponse response){
		log.error(exception.getMessage());
		response.setStatusCode(HttpStatus.FORBIDDEN);
		if(Checker.BeNotNull(exception.getCause())){
			return ApiResult.result(HttpStatus.FORBIDDEN.value(),exception.getCause().getMessage());
		}else{
			return ApiResult.result(HttpStatus.FORBIDDEN.value(),exception.getMessage());
		}
	}

	private boolean isCollection(Object body){
		return Collection.class.isInstance(body);
	}

	private boolean isApiResult(Object body){
		return ApiResult.class.isInstance(body);
	}

	private boolean isModelAndView(Object body){
		return ModelAndView.class.isInstance(body);
	}

}
